package cn.okcode.slowjson.internal;

import java.lang.reflect.*;
import java.util.*;

/**
 * @author pyk13
 */
public class TypeUtils {

    /**
     * 获取Type的原始类型<br/>
     * 这里的原始类型，即Class，则直接返回{@code (Class<?>)type }<br/><br/>
     * 如果是泛型，则获取到泛型的原始类型，比如 {@code Map<String,Integer>}的原始类型是Map，泛型参数是String和Integer
     *
     * @param type 泛型、数组或者其它基本类型
     * @return 原始类型，可通过反射进行实例化
     */
    public static Class<?> getRawType(Type type) {
        if (type instanceof Class) {
            return (Class<?>) type;
        }
        if (type instanceof ParameterizedType) {
            Type rawType = ((ParameterizedType) type).getRawType();
            if (rawType instanceof Class<?>) {
                return (Class<?>) rawType;
            }
        }
        throw new TypeHandleException("无法处理的错误");
    }

    /**
     * 获取数组元素的类型或者集合的泛型类型
     * 如果不是数组或者Collection则返回null
     *
     * @param type 数组或者集合类型，不会校验参数，错误的类型传入 会返回null
     * @return 数组元素的类型或者集合的泛型类型，如果不是数组或者Collection则返回null
     */
    public static Type getComponentType(Type type) {
        Type componentType = null;
        if (type instanceof Class) {
            Class<?> clazz = (Class<?>) type;
            if (clazz.isArray()) {
                componentType = clazz.getComponentType();
            }
        } else {
            ParameterizedType parameterizedType;
            if (type instanceof ParameterizedType) {
                parameterizedType = (ParameterizedType) type;
                Class<?> rawType = (Class<?>) parameterizedType.getRawType();
                if (Collection.class.isAssignableFrom(rawType)) {
                    Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                    Type actualType = actualTypeArguments[0];
                    if (actualType instanceof Class) {
                        componentType = actualType;
                    }
                }
            } else if (type instanceof GenericArrayType) {
                componentType = ((GenericArrayType) type).getGenericComponentType();
            }
        }
        return componentType;
    }

    /**
     * 获取指定索引位置的泛型的类型参数<br/>
     * <p>
     * 比如 {@code Map<String,Integer>} 原始类型是Map,位置0的泛型参数是{@link String},位置1的泛型参数是 {@link Integer}
     *
     * @param type  泛型类型
     * @param index 类型参数位置, 从0开始 如果不存在则抛异常
     * @return 类型参数
     */
    public static Type getGenericTypeArgument(Type type, int index) {
        if (type instanceof ParameterizedType) {
            Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
            if (actualTypeArguments.length <= index) {
                throw new IndexOutOfBoundsException("索引超过了泛型参数个数,type："
                        + type.getTypeName() + ",index:" + index);
            }
            return actualTypeArguments[index];
        }
        throw new TypeHandleException("无法处理的错误");
    }

    public static boolean isParameterizedType(Type type) {
        return type instanceof ParameterizedType;
    }

    /**
     * 获取类的所有非静态字段
     *
     * @param clazz 类
     * @return 字段对象集合
     */
    public static List<Field> getFields(Class<?> clazz) {
        Field[] fields = clazz.getDeclaredFields();
        List<Field> fileList = new ArrayList<>(fields.length);
        for (Field field : fields) {
            if (Modifier.isStatic(field.getModifiers())) {
                continue;
            }
            fileList.add(field);
        }
        return fileList;
    }

    /**
     * 判断指定类型是否是数组类型
     *
     * @param type Type类型对象
     * @return true-数组或者泛型数组,其它 false
     */
    public static boolean isArray(Type type) {
        if (type instanceof GenericArrayType) {
            return true;
        }
        Type rawType = type;
        if (type instanceof ParameterizedType) {
            rawType = ((ParameterizedType) type).getRawType();
        }
        if (rawType instanceof Class) {
            return ((Class<?>) rawType).isArray();
        }
        return false;
    }

    /**
     * 判断指定类型是否是集合，这里特指实现了{@code java.util.Collection}的集合
     *
     * @param type Type类型对象
     * @return true-集合，false-非集合
     */
    public static boolean isCollection(Type type) {
        Type rawType = type;
        if (type instanceof ParameterizedType) {
            rawType = ((ParameterizedType) type).getRawType();
        }
        if (rawType instanceof Class) {
            return Collection.class.isAssignableFrom((Class<?>) rawType);
        }
        return false;
    }

    /**
     * 根据Type实例化对象
     *
     * @param type 对象类型
     * @return type的实例
     */
    public static Object newInstance(Type type) {
        Type rawType = type;
        if (rawType instanceof ParameterizedType) {
            rawType = ((ParameterizedType) type).getRawType();
        }
        if (rawType instanceof Class) {
            return newInstance((Class<?>) rawType);
        }
        if (type instanceof GenericArrayType) {
            throw new TypeHandleException("数组不应该走到这里来");
        }
        throw new TypeHandleException("无法处理的错误");
    }

    /**
     * 根据Class实例化对象
     * <br/>
     * <br/>
     * 抽象类型只支持集合类型{@link Collection},{@link List}或者{@link AbstractList}和{@link Map}类型
     *
     * @param clazz 类对象
     * @return clazz的实例
     */
    public static Object newInstance(Class<?> clazz) {
        Object object;
        boolean isAbstract = Modifier.isAbstract(clazz.getModifiers());
        if (isAbstract) {
            if (clazz.equals(Collection.class) || clazz.equals(List.class)
                    || clazz.equals(AbstractList.class)) {
                //LinkedList 实现了上面三种类型
                object = new LinkedList<>();
            } else if (clazz.equals(Map.class)) {
                object = new LinkedHashMap<>();
            } else if (clazz.isArray()) {
                throw new TypeHandleException("创建数组需要提供元素数量，class：" + clazz.getName());
            } else {
                throw new TypeHandleException("无法创建抽象类:" + clazz.getName());
            }
        } else {
            try {
                object = clazz.newInstance();
            } catch (InstantiationException | IllegalAccessException e) {
                throw new TypeHandleException("创建对象出错:" + clazz.getName());
            }
        }
        return object;
    }

    /**
     * 创建数组实例
     *
     * @param type 数组元素类型
     * @param size 元素个数
     * @return 数组对象
     */
    public static Object newArrayInstance(Type type, int size) {
        if (type instanceof Class) {
            return Array.newInstance((Class<?>) type, size);
        } else if (type instanceof ParameterizedType) {
            Type rawType = ((ParameterizedType) type).getRawType();
            if (rawType instanceof Class) {
                return Array.newInstance((Class<?>) rawType, size);
            }
        }
        throw new TypeHandleException("无法处理的错误");
    }
}
